package algorithm.combination;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;


public class CombinationNonDuplicate {
    int[] dataArray;

    public CombinationNonDuplicate(int[] dataArray) {
        this.dataArray = dataArray;
    }

    public void visit(int expectLength, Consumer<int[]> onVisit) {
        Map<Integer, Integer> countMap = Arrays.stream(dataArray).boxed().
                collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(it -> 1)));
        int[] visitedState = new int[countMap.size()];
        int[] newDataArray = new int[countMap.size()];
        int index = 0;
        for (Map.Entry<Integer, Integer> integerIntegerEntry : countMap.entrySet()) {
            newDataArray[index] = integerIntegerEntry.getKey();
            visitedState[index] = integerIntegerEntry.getValue();
            index++;
        }
        doVisit(expectLength, onVisit, newDataArray, visitedState, new int[dataArray.length], 0, 0);
    }

    private void doVisit(int expectLength, Consumer<int[]> onVisit, int[] dataArray, int[] visitedState,
                         int[] context, int resultLength, int toVisitIndex) {
        if (resultLength == expectLength) {
            onVisit.accept(Arrays.copyOf(context, expectLength));
        } else {
            if (toVisitIndex < dataArray.length) {
                if (visitedState[toVisitIndex] > 0) {
                    visitedState[toVisitIndex]--;
                    context[resultLength] = dataArray[toVisitIndex];
                    doVisit(expectLength, onVisit, dataArray, visitedState, context, resultLength + 1, toVisitIndex);
                    doVisit(expectLength, onVisit, dataArray, visitedState, context, resultLength, toVisitIndex + 1);
                    visitedState[toVisitIndex]++;
                } else {
                    doVisit(expectLength, onVisit, dataArray, visitedState, context, resultLength, toVisitIndex + 1);
                }
            }
        }
    }
}
